<?php
// +----------------------------------------------------------------------
// | Bwsaas
// +----------------------------------------------------------------------
// | Copyright (c) 2015~2020 http://www.buwangyun.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Gitee ( https://gitee.com/buwangyun/bwsaas )
// +----------------------------------------------------------------------
// | Author: buwangyun <hnlg666@163.com>
// +----------------------------------------------------------------------
// | Date: 2020-9-28 10:55:00
// +----------------------------------------------------------------------

namespace buwang\service;
use app\manage\model\Member;
use buwang\exception\AuthException;
use app\manage\model\AuthGroupNode;
use app\manage\model\AuthGroup;
use app\manage\model\AuthNode;
use app\manage\model\AuthGroupAccess;
use app\manage\model\Admin;

/**权限认证服务
 * Class AuthService
 * @package buwang\service
 */
class AuthService
{
    protected $action;
    /**
     * @var object 对象实例
     */
    protected static $instance;
    /**
     * 初始化
     * @access public
     * @return AuthService
     */
    public static function instance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new static();
        }

        return self::$instance;
    }
    /**
     * 检测当前控制器和方法是否匹配传递的数组
     *
     * @param array $arr 需要验证权限的数组
     * @return bool
     */
    public function match($arr = [])
    {
        $arr = is_array($arr) ? $arr : explode(',', (string)$arr);
        if (!$arr) {
            return false;
        }

        $arr = array_map('strtolower', $arr);
        // 是否存在
        if (in_array(strtolower($this->getAction()), $arr) || in_array('*', $arr)) {
            return true;
        }

        // 没找到匹配
        return false;
    }

    /**
     * 获取应用的授权菜单树
     *
     * @param int    $uid
     * @param string $login_type
     * @param string $app
     *
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function getAppAuthTree(int $uid, string $login_type, string $app):array {
        $accessGroupIds = AuthGroupAccess::where('uid', $uid)
            ->where('scopes', $login_type)
            ->column('group_id');

        if (empty($accessGroupIds)) {
            return [];
        }
        $groupIds = AuthGroup::where('id', 'in', $accessGroupIds)
            ->where('status', 1)
            ->column('id');

        if (empty($groupIds)) {
            return [];
        }
        $authedGroupNodeIds = AuthGroupNode::where('group_id', 'in', $groupIds)
            ->column('node_id');

        $nodes = AuthNode::where('status', 1)
            ->where('app_name', $app)
            ->where('type', 'app')
            ->select()
            ->toArray();

        if (empty($nodes)) {
            return [];
        }

        $menuPaths = [];
        foreach ($nodes as $node) {
            if (in_array($node['id'], $authedGroupNodeIds)) {
                $menuPaths[] = $node['menu_path'];
            }
        }

        return [
            'menuPaths' => $menuPaths,
            'menuTree'  => self::_buildMenuChildTree(0, $nodes, $authedGroupNodeIds),
        ];
    }

    protected static function _buildMenuChildTree(int $pid, array $menus, array $authedNodeIds):array {
        $tree = [];
        foreach ($menus as $menu) {
            if ($pid == $menu['pid']) {
                if ($menu['pid'] !== 0 && !in_array($menu['id'], $authedNodeIds)) {
                    continue;
                }
                $n        = [
                    'id'       => $menu['id'],
                    'name'     => $menu['title'],
                    'path'     => $menu['menu_path'],
                    'children' => [],
                ];
                $children = self::_buildMenuChildTree(
                    $menu['id'],
                    $menus,
                    $authedNodeIds
                );
                if (!empty($children)) {
                    $n['children'] = $children;
                    $n['path']     = '';// 存在子菜单则父级无 path.
                }
                $tree[] = $n;
            }
        }

        return $tree;
    }

    /**权限验证方法
     * @param $user :登录用户对象或登录用户id
     * @param $login_type
     * @param $node_name
     * @return mixed
     */
    public static function auth($user,$login_type,$node_name){
            //查询该管理员是否拥有该节点权限
            switch ($login_type) {
                case "member":
                    if(is_numeric($user))$user = Member::where('id',(int)$user)->find();
                    if (!$user)throw new AuthException('找不到用户信息');
                    //如果是子租户鉴权走子租户
                     if($user['sub_member_id'])$user['id'] = $user['sub_member_id'];
                    $group_ids = AuthGroupAccess::where('uid', $user['id'])->where('scopes', $login_type)->column('group_id');
                    //过滤无效的角色
                    $group_ids = AuthGroup::where('id', 'in', $group_ids)->where('status', 1)->column('id');
                    $groupNode = AuthGroupNode::where('node_name', $node_name)->where('group_id', 'in', $group_ids)->find();

                    if ($groupNode) $groupNode = AuthNode::where('status', 1)->find($groupNode['node_id']);
                    //过滤掉无效节点
                    if (!$groupNode)throw new AuthException('无操作权限',403);
                    break;
                case "admin":
                    if(is_numeric($user))$user = Admin::where('id',(int)$user)->find();
                    if (!$user)throw new AuthException('找不到用户信息');
                    $topAdminId = config('auth.super_admin_id');//超级管理员id
                    $topAdminRoleId = config('auth.super_admin_role_id');//超级管理员角色
                    $admin = Admin::find($user['id']);
                    if (!$admin)throw new AuthException('找不到用户信息');
                    //不是系统唯一超管需要鉴权
                    if ($admin['id'] != $topAdminId) {
                        $group_ids = AuthGroupAccess::where('uid', $user['id'])->where('scopes', $login_type)->column('group_id');
                        //如果没有超级管理员角色则需要鉴权
                        if (!in_array($topAdminRoleId, $group_ids)) {
                            //过滤无效的角色
                            $group_ids = AuthGroup::where('id', 'in', $group_ids)->where('status', 1)->column('id');
                            $groupNode = AuthGroupNode::where('node_name', $node_name)->where('group_id', 'in', $group_ids)->find();
                            if ($groupNode) $groupNode = AuthNode::where('status', 1)->find($groupNode['node_id']);
                            // echo AuthGroupNode::getLastSql();die;//打印最后一条sql
                            if (!$groupNode) throw new AuthException('无操作权限',403);
                        }
                    }
                    break;
                default:
                    //TODO
                    break;
            }


    }

    /**
     * @return mixed
     */
    public function getAction()
    {
        return $this->action;
    }

    /**
     * @param mixed $action
     */
    public function setAction($action): void
    {
        $this->action = $action;
    }

}